import traceback
from PyQt5 import QtGui
from PyQt5.QtCore import Qt
from PyQt5.QtMultimedia import QSound
from PyQt5.QtWidgets import QMainWindow, QMessageBox, QLabel
from PyQt5.QtGui import QPalette, QPixmap, QIcon

from game_new import Gomoku


class LaBel(QLabel):
    def __init__(self, parent):
        super().__init__(parent)
        self.setMouseTracking(True)

    def enterEvent(self, e):
        e.ignore()


def run_with_exc(f):
    # 游戏运行出现错误时，用messagebox把错误信息显示出来

    def call(window, *args, **kwargs):
        try:
            return f(window, *args, **kwargs)
        except Exception:
            exc_info = traceback.format_exc()
            QMessageBox.about(window, '错误信息', exc_info)

    return call


class GomokuWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.init_ui()  # 初始化游戏界面
        self.g = Gomoku()  # 初始化游戏内容
        self.black_piece = QPixmap('img/black.png')
        self.white_piece = QPixmap('img/white.png')
        self.sound_piece = QSound("sound/move.wav")
        self.sound_win = QSound("sound/win.wav")
        self.sound_defeated = QSound("sound/defeated.wav")

    def init_ui(self):
        # 初始化棋盘
        self.setObjectName('MainWindow')
        self.setWindowTitle('五子棋')
        self.setFixedSize(540, 540)
        self.setWindowTitle("Gomoku")  # 窗口名称
        self.setWindowIcon(QIcon('img/yellow.png'))  # 窗口图标
        palette = QPalette()  # 设置棋盘背景
        palette.setBrush(self.backgroundRole(), QtGui.QBrush(QtGui.QPixmap('img/chessboard.jpg')))
        self.setPalette(palette)

        self.setCursor(Qt.PointingHandCursor)  # 将鼠标箭头改成小手指
        self.mouse_point = LaBel(self)  # 将鼠标图片改为棋子
        self.mouse_point.setScaledContents(True)
        self.mouse_point.setPixmap(QPixmap('img/black.png'))  # 加载黑棋
        self.mouse_point.setGeometry(270, 270, 34, 34)

        self.pieces = [LaBel(self) for i in range(225)]  # 初始化225个LaBel，用于显示棋子图片
        for piece in self.pieces:
            piece.setVisible(True)  # 图片可视
            piece.setScaledContents(True)  # 图片大小根据标签大小可变

        self.mouse_point.raise_()  # 鼠标始终在最上层
        self.setMouseTracking(True)
        self.show()

    def mouseMoveEvent(self, e):  # 黑色棋子随鼠标移动
        self.mouse_point.move(e.x() - 16, e.y() - 16)

    @run_with_exc
    def paintEvent(self, e):
        # 绘制游戏内容
        # 绘制棋子
        # 1 绘制黑棋子
        i = 0
        for x in range(15):
            for y in range(15):
                if self.g.g_map[x][y] == 1:
                    self.pieces[i].setPixmap(self.black_piece)
                    self.pieces[i].setGeometry(int(35.4 * x + 22 - 34 / 2), int(35.4 * y + 22 - 34 / 2), 34, 34)
                    i += 1
        # 2 绘制白棋子
        for x in range(15):
            for y in range(15):
                if self.g.g_map[x][y] == 2:
                    self.pieces[i].setPixmap(self.white_piece)
                    self.pieces[i].setGeometry(int(35.4 * x + 22 - 34 / 2), int(35.4 * y + 22 - 34 / 2), 34, 34)
                    i += 1

    @run_with_exc
    def mousePressEvent(self, e):
        # 根据鼠标的动作确定落子位置
        if e.button() == Qt.LeftButton:
            # 1 首先判断下在了哪个格子
            mouse_x = e.windowPos().x()
            mouse_y = e.windowPos().y()
            if ((mouse_x - 22) % 35.4 <= 15 or (mouse_x - 22) % 35.4 >= 15) and (
                    (mouse_y - 22) % 35.4 <= 15 or (mouse_y - 22) % 35.4 >= 15):
                game_x = int((mouse_x - 22 + 15) // 35.4)
                game_y = int((mouse_y - 22 + 15) // 35.4)
            else:
                # 鼠标点击位置不正确
                return
            self.g.move_1step(True, game_x, game_y)
            self.sound_piece.play()
            self.repaint()
            # 2 根据操作进行一轮游戏循环
            res = self.g.game_result()
            if res != 0:
                self.repaint()
                self.game_restart(res)
                return
            self.g.ai_move_1step()
            res = self.g.game_result()
            if res != 0:
                self.repaint()
                self.game_restart(res)
                return
            self.repaint()

    def game_restart(self, res):
        # 游戏重新开始
        # 1 显示游戏结束的信息
        if res == 1:
            self.sound_win.play()
            QMessageBox.about(self, '游戏结束', '玩家获胜!')
        elif res == 2:
            self.sound_defeated.play()
            QMessageBox.about(self, '游戏结束', 'AI获胜!')
        elif res == 3:
            QMessageBox.about(self, '游戏结束', '平局!')
        else:
            raise ValueError('当前游戏结束的标志位为' + self.res + '. 而游戏结束的标志位必须为1, 2 或 3')
        # 2 游戏重新开始的操作
        self.g = Gomoku()
        for i in range(225):
            self.pieces[i].setPixmap(QPixmap(""))
        self.repaint()
